View Javadoc
1   package edu.jiangxin.apktoolbox.main;
2   
3   import edu.jiangxin.apktoolbox.Version;
4   import edu.jiangxin.apktoolbox.android.dumpsys.DumpsysPanel;
5   import edu.jiangxin.apktoolbox.convert.color.ColorPickerPanel;
6   import edu.jiangxin.apktoolbox.file.batchrename.BatchRenamePanel;
7   import edu.jiangxin.apktoolbox.file.EncodeConvertPanel;
8   import edu.jiangxin.apktoolbox.file.OsConvertPanel;
9   import edu.jiangxin.apktoolbox.file.checksum.ChecksumPanel;
10  import edu.jiangxin.apktoolbox.file.password.recovery.RecoveryPanel;
11  import edu.jiangxin.apktoolbox.file.duplicate.DuplicateSearchPanel;
12  import edu.jiangxin.apktoolbox.file.zhconvert.ZhConvertPanel;
13  import edu.jiangxin.apktoolbox.help.*;
14  import edu.jiangxin.apktoolbox.android.i18n.I18nAddPanel;
15  import edu.jiangxin.apktoolbox.android.i18n.I18nFindLongestPanel;
16  import edu.jiangxin.apktoolbox.android.i18n.I18nRemovePanel;
17  import edu.jiangxin.apktoolbox.android.monkey.MonkeyPanel;
18  import edu.jiangxin.apktoolbox.help.settings.SettingsPanel;
19  import edu.jiangxin.apktoolbox.pdf.finder.PdfFinderPanel;
20  import edu.jiangxin.apktoolbox.pdf.passwordremover.PdfPasswordRemoverPanel;
21  import edu.jiangxin.apktoolbox.pdf.pic2pdf.Pic2PdfPanel;
22  import edu.jiangxin.apktoolbox.pdf.stat.PdfStatPanel;
23  import edu.jiangxin.apktoolbox.reverse.*;
24  import edu.jiangxin.apktoolbox.android.screenshot.ScreenShotPanel;
25  import edu.jiangxin.apktoolbox.reverse.ApktoolPanel;
26  import edu.jiangxin.apktoolbox.swing.extend.EasyFrame;
27  import edu.jiangxin.apktoolbox.swing.extend.EasyPanel;
28  import edu.jiangxin.apktoolbox.swing.extend.listener.ChangeMenuListener;
29  import edu.jiangxin.apktoolbox.swing.extend.listener.ChangeMenuToUrlListener;
30  import edu.jiangxin.apktoolbox.swing.extend.listener.IPreChangeMenuCallBack;
31  import edu.jiangxin.apktoolbox.swing.extend.plugin.ChangeMenuPreparePluginController;
32  import edu.jiangxin.apktoolbox.swing.extend.plugin.PluginPanel;
33  import edu.jiangxin.apktoolbox.swing.keeper.UiStateKeeper;
34  import edu.jiangxin.apktoolbox.utils.Utils;
35  import org.apache.commons.configuration2.Configuration;
36  import org.apache.commons.lang3.StringUtils;
37  import org.apache.logging.log4j.LogManager;
38  import org.apache.logging.log4j.Logger;
39  
40  import javax.swing.*;
41  import javax.swing.border.EmptyBorder;
42  import java.awt.*;
43  import java.awt.event.*;
44  import java.io.Serial;
45  import java.lang.reflect.InvocationTargetException;
46  import java.text.MessageFormat;
47  import java.util.Locale;
48  import java.util.Objects;
49  
50  /**
51   * @author jiangxin
52   * @author 2018-08-19
53   */
54  public final class MainFrame extends EasyFrame {
55  
56      @Serial
57      private static final long serialVersionUID = 1L;
58  
59      private JPanel contentPane;
60      private EasyPanel currentEasyPanel = null;
61      private JMenuBar menuBar;
62  
63      public static void main(String[] args) {
64          final Logger logger = LogManager.getLogger(MainFrame.class.getSimpleName());
65          boolean isEnvironmentOk = Utils.checkAndInitEnvironment();
66          if (!isEnvironmentOk) {
67              logger.error("Environment is not ready, exit");
68              return;
69          }
70          EventQueue.invokeLater(() -> {
71              Configuration conf = Utils.getConfiguration();
72              String lookAndFeelClassName = conf.getString("look.and.feel.class.name");
73              if (StringUtils.isEmpty(lookAndFeelClassName)) {
74                  lookAndFeelClassName = "com.formdev.flatlaf.FlatDarculaLaf";
75                  conf.setProperty("look.and.feel.class.name", lookAndFeelClassName);
76              }
77              try {
78                  UIManager.setLookAndFeel(lookAndFeelClassName);
79              } catch (UnsupportedLookAndFeelException | ClassNotFoundException | InstantiationException | IllegalAccessException e) {
80                  logger.error("setLookAndFeel failed, use default instead", e);
81              }
82  
83              String currentLocaleLanguage = conf.getString("locale.language");
84              if (StringUtils.isEmpty(currentLocaleLanguage)) {
85                  currentLocaleLanguage = Locale.ENGLISH.getLanguage();
86                  conf.setProperty("locale.language", currentLocaleLanguage);
87              }
88              Locale.setDefault(Locale.forLanguageTag(currentLocaleLanguage));
89  
90              MainFrame frame = new MainFrame();
91  
92              boolean isAlwaysOnTop = conf.getBoolean("always.on.top", false);
93              conf.setProperty("always.on.top", isAlwaysOnTop);
94              frame.setAlwaysOnTop(isAlwaysOnTop);
95  
96              frame.setVisible(true);
97          });
98      }
99  
100     public MainFrame() {
101         super();
102         initialize();
103         if (SystemTray.isSupported()) {
104             configSystemTray();
105         }
106 
107         setTitle(MessageFormat.format(bundle.getString("main.title"), Version.VERSION));
108         setDefaultCloseOperation(EXIT_ON_CLOSE);
109         setMenuBar();
110         contentPane = new JPanel();
111         contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
112         contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));
113         contentPane.add(Box.createVerticalGlue());
114         EasyPanel initPanel = new AboutPanel();
115         initPanel.init();
116         initPanel.setBorder(BorderFactory.createTitledBorder(bundle.getString("help.about.title")));
117         contentPane.add(initPanel);
118         contentPane.add(Box.createVerticalGlue());
119         setContentPane(contentPane);
120         refreshSizeAndLocation();
121     }
122 
123     private void configSystemTray() {
124         SystemTray systemTray = SystemTray.getSystemTray();
125         PopupMenu popupMenu = new PopupMenu();
126         final MenuItem show = new MenuItem("Open");
127         final MenuItem exit = new MenuItem("Close");
128         ActionListener actionListener = e -> {
129             if (e.getSource() == show) {
130                 setExtendedState(NORMAL);
131                 setVisible(true);
132             }
133             if (e.getSource() == exit) {
134                 dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING));
135             }
136         };
137         exit.addActionListener(actionListener);
138         show.addActionListener(actionListener);
139         popupMenu.add(show);
140         popupMenu.add(exit);
141         TrayIcon trayIcon = new TrayIcon(image, "系统托盘", popupMenu);
142         trayIcon.setImageAutoSize(true);
143         try {
144             systemTray.add(trayIcon);
145         } catch (AWTException e) {
146             logger.error("add icon to tray failed");
147         }
148         trayIcon.addMouseListener(new MouseAdapter() {
149             @Override
150             public void mouseClicked(MouseEvent e) {
151                 if (e.getClickCount() == 2) {
152                     setExtendedState(NORMAL);
153                     setVisible(true);
154                 }
155             }
156         });
157     }
158 
159     private void setMenuBar() {
160         menuBar = new JMenuBar();
161         setJMenuBar(menuBar);
162 
163         createReverseMenu();
164 
165         createAndroidMenu();
166 
167         createPdfMenu();
168 
169         createFileMenu();
170 
171         createConvertMenu();
172 
173         createHelpMenu();
174     }
175 
176     private void createHelpMenu() {
177         JMenu helpMenu = new JMenu(bundle.getString("help.title"));
178         menuBar.add(helpMenu);
179 
180         JMenuItem documentMenuItem = new JMenuItem(bundle.getString("help.document.title"));
181         documentMenuItem.addActionListener(new ChangeMenuToUrlListener(Constant.URL_DOCUMENT));
182         helpMenu.add(documentMenuItem);
183 
184         JMenuItem settingsMenuItem = new JMenuItem(bundle.getString("help.settings.title"));
185         settingsMenuItem.addActionListener(new ChangeMenuToPanelListener(SettingsPanel.class, settingsMenuItem.getText()));
186         helpMenu.add(settingsMenuItem);
187 
188         JMenuItem feedbackMenuItem = new JMenuItem(bundle.getString("help.feedback.title"));
189         feedbackMenuItem.addActionListener(new ChangeMenuToUrlListener(Constant.URL_FEEDBACK));
190         helpMenu.add(feedbackMenuItem);
191 
192         JMenuItem checkUpdateMenuItem = new JMenuItem(bundle.getString("help.checkupdate.title"));
193         checkUpdateMenuItem.addActionListener(new CheckUpdateActionListener(this));
194         helpMenu.add(checkUpdateMenuItem);
195 
196         JMenuItem contributeMenuItem = new JMenuItem(bundle.getString("help.contribute.title"));
197         contributeMenuItem.addActionListener(new ChangeMenuToUrlListener(Constant.URL_CONTRIBUTE));
198         helpMenu.add(contributeMenuItem);
199 
200         JMenuItem aboutMenuItem = new JMenuItem(bundle.getString("help.about.title"));
201         aboutMenuItem.addActionListener(new ChangeMenuToPanelListener(AboutPanel.class, aboutMenuItem.getText()));
202         helpMenu.add(aboutMenuItem);
203     }
204 
205     private void createPdfMenu() {
206         JMenu pdfMenu = new JMenu(bundle.getString("pdf.title"));
207         menuBar.add(pdfMenu);
208 
209         JMenuItem pdfStatMenuItem = new JMenuItem(bundle.getString("pdf.stat.title"));
210         pdfStatMenuItem.addActionListener(new ChangeMenuToPanelListener(PdfStatPanel.class, pdfStatMenuItem.getText()));
211         pdfMenu.add(pdfStatMenuItem);
212 
213         JMenuItem pdfFinderMenuItem = new JMenuItem(bundle.getString("pdf.finder.title"));
214         pdfFinderMenuItem.addActionListener(new ChangeMenuToPanelListener(PdfFinderPanel.class, pdfFinderMenuItem.getText()));
215         pdfMenu.add(pdfFinderMenuItem);
216 
217         JMenuItem pdfPasswordRemoverMenuItem = new JMenuItem(bundle.getString("pdf.password.remover.title"));
218         pdfPasswordRemoverMenuItem.addActionListener(new ChangeMenuToPanelListener(PdfPasswordRemoverPanel.class, pdfPasswordRemoverMenuItem.getText()));
219         pdfMenu.add(pdfPasswordRemoverMenuItem);
220 
221         JMenuItem pic2PdfMenuItem = new JMenuItem(bundle.getString("pictures.to.pdf.title"));
222         pic2PdfMenuItem.addActionListener(new ChangeMenuToPanelListener(Pic2PdfPanel.class, pic2PdfMenuItem.getText()));
223         pdfMenu.add(pic2PdfMenuItem);
224     }
225 
226     private void createFileMenu() {
227         JMenu fileMenu = new JMenu(bundle.getString("file.title"));
228         menuBar.add(fileMenu);
229 
230         JMenuItem osConvertMenuItem = new JMenuItem(bundle.getString("file.os.convert.title"));
231         osConvertMenuItem.addActionListener(new ChangeMenuToPanelListener(OsConvertPanel.class, osConvertMenuItem.getText()));
232         fileMenu.add(osConvertMenuItem);
233 
234         JMenuItem encodeConvertMenuItem = new JMenuItem(bundle.getString("file.encode.convert.title"));
235         encodeConvertMenuItem.addActionListener(new ChangeMenuToPanelListener(EncodeConvertPanel.class, encodeConvertMenuItem.getText()));
236         fileMenu.add(encodeConvertMenuItem);
237 
238         JMenuItem zhConvertMenuItem = new JMenuItem(bundle.getString("file.zh.convert.title"));
239         zhConvertMenuItem.addActionListener(new ChangeMenuToPanelListener(ZhConvertPanel.class, zhConvertMenuItem.getText()));
240         fileMenu.add(zhConvertMenuItem);
241 
242         JMenuItem duplicateFindMenuItem = new JMenuItem(bundle.getString("file.duplicate.title"));
243         duplicateFindMenuItem.addActionListener(new ChangeMenuToPanelListener(DuplicateSearchPanel.class, duplicateFindMenuItem.getText()));
244         fileMenu.add(duplicateFindMenuItem);
245 
246         JMenuItem batchRenameMenuItem = new JMenuItem(bundle.getString("file.batch.rename.title"));
247         batchRenameMenuItem.addActionListener(new ChangeMenuToPanelListener(BatchRenamePanel.class, batchRenameMenuItem.getText()));
248         fileMenu.add(batchRenameMenuItem);
249 
250         JMenuItem checkSumMenuItem = new JMenuItem(bundle.getString("file.check.summary.title"));
251         checkSumMenuItem.addActionListener(new ChangeMenuToPanelListener(ChecksumPanel.class, checkSumMenuItem.getText()));
252         fileMenu.add(checkSumMenuItem);
253 
254         JMenuItem recoveryMenuItem = new JMenuItem(bundle.getString("file.password.recovery.title"));
255         recoveryMenuItem.addActionListener(new ChangeMenuToPanelListener(RecoveryPanel.class, recoveryMenuItem.getText()));
256         fileMenu.add(recoveryMenuItem);
257     }
258 
259     private void createConvertMenu() {
260         JMenu othersMenu = new JMenu(bundle.getString("others.title"));
261         menuBar.add(othersMenu);
262 
263         JMenuItem colorPickerMenuItem = new JMenuItem(bundle.getString("picker.color.title"));
264         colorPickerMenuItem.addActionListener(new ChangeMenuToPanelListener(ColorPickerPanel.class, colorPickerMenuItem.getText()));
265         othersMenu.add(colorPickerMenuItem);
266     }
267 
268     private void createAndroidMenu() {
269         JMenu androidMenu = new JMenu(bundle.getString("android.title"));
270         menuBar.add(androidMenu);
271 
272         JMenuItem i18nAddMenuItem = new JMenuItem(bundle.getString("android.i18n.add.title"));
273         i18nAddMenuItem.addActionListener(new ChangeMenuToPanelListener(I18nAddPanel.class, i18nAddMenuItem.getText()));
274         androidMenu.add(i18nAddMenuItem);
275 
276         JMenuItem i18nFindLongestMenuItem = new JMenuItem(bundle.getString("android.i18n.longest.title"));
277         i18nFindLongestMenuItem.addActionListener(new ChangeMenuToPanelListener(I18nFindLongestPanel.class, i18nFindLongestMenuItem.getText()));
278         androidMenu.add(i18nFindLongestMenuItem);
279 
280         JMenuItem i18nRemoveMenuItem = new JMenuItem(bundle.getString("android.i18n.remove.title"));
281         i18nRemoveMenuItem.addActionListener(new ChangeMenuToPanelListener(I18nRemovePanel.class, i18nRemoveMenuItem.getText()));
282         androidMenu.add(i18nRemoveMenuItem);
283 
284         JMenuItem screenShotMenuItem = new JMenuItem(bundle.getString("android.screenshot.title"));
285         screenShotMenuItem.addActionListener(new ChangeMenuToPanelListener(ScreenShotPanel.class, screenShotMenuItem.getText()));
286         screenShotMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK));
287         androidMenu.add(screenShotMenuItem);
288 
289         JMenuItem monkeyMenuItem = new JMenuItem(bundle.getString("android.monkey.title"));
290         monkeyMenuItem.addActionListener(new ChangeMenuToPanelListener(MonkeyPanel.class, monkeyMenuItem.getText()));
291         androidMenu.add(monkeyMenuItem);
292 
293         JMenuItem dumpsysMenuItem = new JMenuItem(bundle.getString("android.dumpsys.title"));
294         dumpsysMenuItem.addActionListener(new ChangeMenuToPanelListener(DumpsysPanel.class, dumpsysMenuItem.getText()));
295         androidMenu.add(dumpsysMenuItem);
296     }
297 
298     private void createReverseMenu() {
299         JMenu reverseMenu = new JMenu(bundle.getString("reverse.title"));
300         reverseMenu.setMnemonic(KeyEvent.VK_R);
301         menuBar.add(reverseMenu);
302 
303         JMenuItem pluginVersionMenuItem = new JMenuItem(bundle.getString("reverse.plugin.version.title"));
304         pluginVersionMenuItem.addActionListener(new ChangeMenuToUrlListener(Constant.URL_PLUGIN_VERSION));
305         reverseMenu.add(pluginVersionMenuItem);
306 
307         JMenuItem apktoolMenuItem = new JMenuItem(bundle.getString("reverse.apktool.title"), KeyEvent.VK_D);
308         apktoolMenuItem.addActionListener(new ChangeMenuToPanelListener(ApktoolPanel.class, apktoolMenuItem.getText()));
309         reverseMenu.add(apktoolMenuItem);
310 
311         JMenuItem apkSignMenuItem = new JMenuItem(bundle.getString("reverse.apksigner.title"));
312         apkSignMenuItem.addActionListener(new ChangeMenuToPanelListener(ApkSignerPanel.class, apkSignMenuItem.getText()));
313         reverseMenu.add(apkSignMenuItem);
314 
315         JMenuItem jDMenuItem = new JMenuItem(bundle.getString("reverse.jd.gui.title"));
316         jDMenuItem.addActionListener(new ChangeMenToPluginJdListener());
317         reverseMenu.add(jDMenuItem);
318 
319         JMenuItem bytecodeViewerMenuItem = new JMenuItem(bundle.getString("reverse.bytecode.viewer.title"));
320         bytecodeViewerMenuItem.addActionListener(new ChangeMenuToPluginBytecodeViewerListener());
321         reverseMenu.add(bytecodeViewerMenuItem);
322 
323         JMenuItem luytenMenuItem = new JMenuItem(bundle.getString("reverse.luyten.title"));
324         luytenMenuItem.addActionListener(new ChangeMenuToPluginLuytenListener());
325         reverseMenu.add(luytenMenuItem);
326 
327         JMenuItem jdDuoMenuItem = new JMenuItem(bundle.getString("reverse.jd.duo.title"));
328         jdDuoMenuItem.addActionListener(new ChangeMenuToPluginJdDuoListener());
329         reverseMenu.add(jdDuoMenuItem);
330 
331         JMenuItem jdaMenuItem = new JMenuItem(bundle.getString("reverse.jda.title"));
332         jdaMenuItem.addActionListener(new ChangeMenuToPluginJdaListener());
333         reverseMenu.add(jdaMenuItem);
334 
335         JMenuItem jADXMenuItem = new JMenuItem(bundle.getString("reverse.jadx.title"));
336         jADXMenuItem.addActionListener(new ChangeMenuToPluginJadxListener());
337         reverseMenu.add(jADXMenuItem);
338 
339         JMenuItem aXMLPrinter = new JMenuItem(bundle.getString("reverse.axmlprinter.title"));
340         aXMLPrinter.addActionListener(new ChangeMenuToPanelListener(AxmlPrinterPanel.class, aXMLPrinter.getText()));
341         reverseMenu.add(aXMLPrinter);
342     }
343 
344     class ChangeMenuToPanelListener implements ChangeMenuListener {
345 
346         Class<? extends EasyPanel> easyPanelClass;
347 
348         EasyPanel panel = null;
349 
350         String title;
351 
352         public ChangeMenuToPanelListener(Class<? extends EasyPanel> easyPanelClass, String title) {
353             this.easyPanelClass = easyPanelClass;
354             this.title = title;
355             panel = createEasyPanel();
356         }
357 
358         @Override
359         public boolean isNeedPreChangeMenu() {
360             return panel.isNeedPreChangeMenu();
361         }
362 
363         @Override
364         public void onPreChangeMenu(IPreChangeMenuCallBack callBack) {
365             if (panel instanceof PluginPanel pluginPanel) {
366                 pluginPanel.preparePlugin(new ChangeMenuPreparePluginController(pluginPanel.getPluginFilename(), pluginPanel.isPluginNeedUnzip(), pluginPanel.isPluginNeedUnzipToSeparateDir(), callBack));
367             }
368         }
369 
370         @Override
371         public void onChangeMenu() {
372             UiStateKeeper.save(currentEasyPanel);
373             contentPane.removeAll();
374             contentPane.add(Box.createVerticalGlue());
375             panel.init();
376             panel.setBorder(BorderFactory.createTitledBorder(title));
377             contentPane.add(panel);
378             logger.info("Panel changed: " + panel.getClass().getSimpleName());
379             contentPane.add(Box.createVerticalGlue());
380             contentPane.revalidate();
381             contentPane.repaint();
382             refreshSizeAndLocation();
383             panel.afterPainted();
384             UiStateKeeper.restore(panel);
385             currentEasyPanel = panel;
386         }
387 
388         private EasyPanel createEasyPanel() {
389             if (easyPanelClass == null) {
390                 return new EasyPanel();
391             }
392             EasyPanel retEasyPanel = null;
393             try {
394                 retEasyPanel = easyPanelClass.getDeclaredConstructor().newInstance();
395             } catch (InstantiationException | IllegalAccessException | InvocationTargetException |
396                      NoSuchMethodException e) {
397                 logger.info("createEasyPanel failed: {}", e.getMessage());
398             }
399             return Objects.requireNonNullElseGet(retEasyPanel, EasyPanel::new);
400         }
401     }
402 
403     @Override
404     protected void onWindowClosing(WindowEvent e) {
405         super.onWindowClosing(e);
406         UiStateKeeper.save(currentEasyPanel);
407     }
408 
409     @Override
410     protected void onWindowIconified(WindowEvent e) {
411         super.onWindowIconified(e);
412         UiStateKeeper.save(currentEasyPanel);
413     }
414 }